package com.jiangyg.mall.core.utils;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

import java.beans.PropertyDescriptor;
import java.io.StringWriter;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 类描述：Velocity模板工具
 * 
 * @author jiangyg
 * @date 2019-10-11
 * @version 2.0
 */
@SuppressWarnings("unchecked")
public class VelocityUtils {

	/**
	 * 功能描述：使用Velocity模板输出结果字符串
	 * 
	 * @param str    传入Velocity语法的字符串
	 * @param params 传入参数
	 * @return 结果字符串
	 */
	public static String stringEvaluate(final String str, final Object params) throws Exception {
		return stringEvaluate(str, params, null);
	}

	/**
	 * 功能描述：使用Velocity模板输出结果字符串
	 * 
	 * @author jiangyg
	 * @date 2020-12-22
	 * @param str       传入Velocity语法的字符串
	 * @param params    传入参数
	 * @param extParams 扩展参数
	 * @return 结果字符串
	 */
	public static String stringEvaluate(final String str, final Object params, final Map<String, Object> extParams) throws Exception {
		final StringWriter writer = new StringWriter();
		final VelocityEngine ve = new VelocityEngine();
		ve.init();
		final VelocityContext context = buildVelocityContext(params, extParams);
		ve.evaluate(context, writer, StringUtils.EMPTY, str);
		return writer.toString();
	}

	/**
	 * 功能描述：根据参数创建Velocity上下文
	 * 
	 * @author jiangyg
	 * @date 2020-12-22
	 * @param params    参数
	 * @param extParams 扩展参数
	 * @return VelocityContext
	 */
	private static VelocityContext buildVelocityContext(final Object params, final Map<String, Object> extParams) throws Exception {
		final VelocityContext context = new VelocityContext();
		// 参数为空，返回空上下文
		if (params == null && extParams == null) {
			return context;
		}
		// 参数处理
		if (params != null) {
			if (params instanceof DynaBean) {
				final DynaProperty[] descriptors = ((DynaBean) params).getDynaClass().getDynaProperties();
				for (DynaProperty descriptor : descriptors) {
					final String name = descriptor.getName();
					final Object value = ((DynaBean) params).get(name);
					setValue(context, name, value);
				}
			} else if (params instanceof Map) {
				for (Entry<String, Object> entry : ((Map<String, Object>) params).entrySet()) {
					setValue(context, entry.getKey(), entry.getValue());
				}
			} else {
				final PropertyUtilsBean propertyUtils = BeanUtilsBean.getInstance().getPropertyUtils();
				final PropertyDescriptor[] descriptors = propertyUtils.getPropertyDescriptors(params);
				for (PropertyDescriptor descriptor : descriptors) {
					final String name = descriptor.getName();
					if (StringUtils.equals("class", name)) {
						continue;
					}
					setValue(context, name, descriptor.getReadMethod().invoke(params));
				}
			}
		}
		// 扩展参数处理
		if (extParams != null && !extParams.isEmpty()) {
			for (Entry<String, Object> entry : extParams.entrySet()) {
				setValue(context, entry.getKey(), entry.getValue());
			}
		}
		return context;
	}

	/**
	 * 功能描述：设置velocity上下文
	 * <p>
	 * 注意：字符串为空则不进行值设置
	 * 
	 * @author jiangyg
	 * @date 2021-03-25
	 * @param context 上下文
	 * @param name    键
	 * @param value   值
	 */
	private static void setValue(VelocityContext context, String name, Object value) {
		if (StringUtils.isBlank(name)) {
			return;
		}
		if (value instanceof String && StringUtils.EMPTY.equals(value.toString())) {
			return;
		}
		context.put(name, value);
	}

}
